﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml.Linq;

namespace STEditor.Classes
{
    public class STGameXamlLoader
    {

        public STGame Load(string folder)
        {

            if (!Directory.Exists(folder))
            {
                throw new ArgumentException("Folder " + folder + " is empty!", "folder");
            }

            var tilesFolder = new DirectoryInfo(Path.Combine(folder, STGameXamlWriter.TilesFolderName));
            if (!tilesFolder.Exists)
            {
                throw new ArgumentException("Sub folder " + STGameXamlWriter.TilesFolderName + " does not exist in input folder", "folder");
            }

            var gameDataFile = new FileInfo(Path.Combine(folder, STGameXamlWriter.GameDataFileName));
            if (!gameDataFile.Exists)
            {
                throw new ArgumentException("File " + STGameXamlWriter.GameDataFileName + " does not exist in input folder", "folder");
            }


            var game = new STGame();

            XDocument gameData;
            using (var gameDataStream = gameDataFile.OpenRead())
            {
                gameData = XDocument.Load(gameDataStream);
            }

            LoadUsedTiles(game, gameData, folder);
            LoadGameData(game, gameData);

            return game;
        }

        private void LoadUsedTiles(STGame game, XDocument gameData, string folder)
        {

            gameData
                .Descendants()
                .Where(e => e.Name.LocalName.Equals("SpriteFrame"))
                .Select(e => ResourceUriToLocalFolder(GetAttribute(e, "Source"), folder))
                .ToList()
                .ForEach(t => game.TileTypes.Add(t));

        }

        private string ResourceUriToLocalFolder(string resourceUri, string rootFolder)
        {
            string fileName = resourceUri.Replace("/" + STGameXamlWriter.AssemblyName + ";component/", "");
            fileName = Path.Combine(rootFolder, fileName);
            return fileName;
        }

        private void LoadGameData(STGame game, XDocument gameData)
        {

            gameData
                .Descendants()
                .Where(d => d.Name.LocalName.Equals("GameAreaGrid"))
                .Select(e => GetGameArea(game, e))
                .ToList()
                .ForEach(game.GameAreas.Add);

        }

        private STGameArea GetGameArea(STGame game, XElement gameAreaElement)
        {

            var gameArea = new STGameArea
            {
                AreaName = GetAttribute(gameAreaElement, "AreaName"),
                TileWidth = Int32.Parse(GetAttribute(gameAreaElement, "TileWidth")),
                TileHeight = Int32.Parse(GetAttribute(gameAreaElement, "TileHeight")),
                Width = Int32.Parse(GetAttribute(gameAreaElement, "Columns")),
                Height = Int32.Parse(GetAttribute(gameAreaElement, "Rows")),
                Game = game
            };

            gameAreaElement
                .Descendants()
                .Where(d => d.Name.LocalName.Equals("SpriteTile"))
                .Select(e => GetTile(gameArea, e))
                .ToList()
                .ForEach(t => gameArea.SetTile(t.Column, t.Row, t.Image));

            return gameArea;
        }

        private STTile GetTile(STGameArea gameArea, XElement tileElement)
        {

            STFrame tileImage = EmptyTile.EmptyImage;

            string frame = GetAttribute(tileElement, "Frame");

            if (!frame.Equals("{x:Null}"))
            {

                string frameKey = frame.Replace("{StaticResource ", "").Replace("}", "");

                string frameSourceAttribute =
                    tileElement
                        .Document
                        .Descendants()
                        .Where(e => e.Name.LocalName.Equals("SpriteFrame"))
                        .Where(e => GetAttribute(e, "Key").Equals(frameKey))
                        .Select(e => GetAttribute(e, "Source").Replace(STGameXamlWriter.AssemblyName + ";", ""))
                        .First();

                string frameFileName = Path.GetFileName(frameSourceAttribute);

                tileImage =
                    gameArea
                        .Game
                        .TileTypes
                        .Where(t => t.Source != null)
                        .Where(t => Path.GetFileName(t.Source.LocalPath).Equals(frameFileName))
                        .Single();

            }

            return new STTile
            {
                Column = Convert.ToInt32(GetAttribute(tileElement, "X")),
                Row = Convert.ToInt32(GetAttribute(tileElement, "Y")),
                Image = tileImage,
                GameArea = gameArea
            };
        }

        private string GetAttribute(XElement element, string attributeName)
        {
            var attribute = element.Attributes().Where(a => a.Name.LocalName.Equals(attributeName)).FirstOrDefault();

            if (attribute == null)
            {
                return string.Empty;
            }
            return attribute.Value;
        }
    }
}
